Telegram Group & Telegram Channel
🐹 Задача для Go 1.21+: «Контекст отменён, но горутина продолжает работу»

📌 Актуально для: Go 1.21 и новее (введён `context.WithCancelCause`)
🎯 Цель: Понять, почему горутина не завершилась по отменённому контексту

📍 Ситуация:

Ты используешь контекст для управления жизненным циклом горутины. В Go 1.21 ты решил использовать context.WithCancelCause:


package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithCancelCause(context.Background())
go worker(ctx)

time.Sleep(1 * time.Second)
cancel(fmt.Errorf("manual stop"))

time.Sleep(2 * time.Second)
}

func worker(ctx context.Context) {
<-ctx.Done()
fmt.Println("Worker stopped:", context.Cause(ctx))
}


🔍 Ты ожидаешь, что горутина завершится и выведет:


Worker stopped: manual stop


Но вместо этого — программа завершилась без вывода. Почему?

🧩 Вопросы:

1. Почему worker не печатает "Worker stopped: ..."?
2. Что изменилось в context.WithCancelCause по сравнению с WithCancel?
3. Как безопасно читать причину отмены?
4. Как изменить worker, чтобы он корректно завершался?
5. Почему важно не блокироваться на `ctx.Done()`, если возможна гонка?

🛠 Решение:

🔸 В Go 1.21 есть `context.WithCancelCause`, который позволяет задавать причину отмены.
Но `context.Cause(ctx)` вернёт `nil`, **если ты используешь `context.WithCancel`**, либо, если `ctx.Done()` не был срабатывающим.

🔸 В этом коде `worker(ctx)` запускается и сразу блокируется на:

<-ctx.Done()


Но если отмена происходит **до** того, как `worker` успел начать слушать `ctx.Done()`, и ты используешь старую `WithCancel`, `context.Cause` вернёт `nil`.

🔸 **Правильный способ:**

Убедись, что `context.WithCancelCause` действительно используется и `ctx.Done()` слушается вовремя.

Для Go 1.21+ пример рабочий:



func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Worker stopped:", context.Cause(ctx))
return
case <-time.After(100 * time.Millisecond):
fmt.Println("Working...")
}
}
}



🔸 Альтернатива для старых версий Go (<1.21):


ctx, cancel := context.WithCancel(context.Background())
...
fmt.Println("Worker stopped:", ctx.Err()) // вместо Cause


📌 Вывод:
Начиная с Go 1.21, `context.WithCancelCause` даёт более точный контроль за причинами отмены. Но горутины всё равно должны явно проверять `ctx.Done()` через `select`, иначе отмена может пройти незаметно.



tg-me.com/golangtests/790
Create:
Last Update:

🐹 Задача для Go 1.21+: «Контекст отменён, но горутина продолжает работу»

📌 Актуально для: Go 1.21 и новее (введён `context.WithCancelCause`)
🎯 Цель: Понять, почему горутина не завершилась по отменённому контексту

📍 Ситуация:

Ты используешь контекст для управления жизненным циклом горутины. В Go 1.21 ты решил использовать context.WithCancelCause:


package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithCancelCause(context.Background())
go worker(ctx)

time.Sleep(1 * time.Second)
cancel(fmt.Errorf("manual stop"))

time.Sleep(2 * time.Second)
}

func worker(ctx context.Context) {
<-ctx.Done()
fmt.Println("Worker stopped:", context.Cause(ctx))
}


🔍 Ты ожидаешь, что горутина завершится и выведет:


Worker stopped: manual stop


Но вместо этого — программа завершилась без вывода. Почему?

🧩 Вопросы:

1. Почему worker не печатает "Worker stopped: ..."?
2. Что изменилось в context.WithCancelCause по сравнению с WithCancel?
3. Как безопасно читать причину отмены?
4. Как изменить worker, чтобы он корректно завершался?
5. Почему важно не блокироваться на `ctx.Done()`, если возможна гонка?

🛠 Решение:

🔸 В Go 1.21 есть `context.WithCancelCause`, который позволяет задавать причину отмены.
Но `context.Cause(ctx)` вернёт `nil`, **если ты используешь `context.WithCancel`**, либо, если `ctx.Done()` не был срабатывающим.

🔸 В этом коде `worker(ctx)` запускается и сразу блокируется на:

<-ctx.Done()


Но если отмена происходит **до** того, как `worker` успел начать слушать `ctx.Done()`, и ты используешь старую `WithCancel`, `context.Cause` вернёт `nil`.

🔸 **Правильный способ:**

Убедись, что `context.WithCancelCause` действительно используется и `ctx.Done()` слушается вовремя.

Для Go 1.21+ пример рабочий:



func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Worker stopped:", context.Cause(ctx))
return
case <-time.After(100 * time.Millisecond):
fmt.Println("Working...")
}
}
}



🔸 Альтернатива для старых версий Go (<1.21):


ctx, cancel := context.WithCancel(context.Background())
...
fmt.Println("Worker stopped:", ctx.Err()) // вместо Cause


📌 Вывод:
Начиная с Go 1.21, `context.WithCancelCause` даёт более точный контроль за причинами отмены. Но горутины всё равно должны явно проверять `ctx.Done()` через `select`, иначе отмена может пройти незаметно.

BY Go tests


Warning: Undefined variable $i in /var/www/tg-me/post.php on line 283

Share with your friend now:
tg-me.com/golangtests/790

View MORE
Open in Telegram


Go tests Telegram | DID YOU KNOW?

Date: |

How Does Telegram Make Money?

Telegram is a free app and runs on donations. According to a blog on the telegram: We believe in fast and secure messaging that is also 100% free. Pavel Durov, who shares our vision, supplied Telegram with a generous donation, so we have quite enough money for the time being. If Telegram runs out, we will introduce non-essential paid options to support the infrastructure and finance developer salaries. But making profits will never be an end-goal for Telegram.

At a time when the Indian stock market is peaking and has rallied immensely compared to global markets, there are companies that have not performed in the last 10 years. These are definitely a minor portion of the market considering there are hundreds of stocks that have turned multibagger since 2020. What went wrong with these stocks? Reasons vary from corporate governance, sectoral weakness, company specific and so on. But the more important question is, are these stocks worth buying?

Go tests from jp


Telegram Go tests
FROM USA